//下面是面向过程的写法
#include <iostream>
#include <cstring>
using namespace std;

const int N = 100010;
const int M = N * 2;
int h[N], e[M], ne[M], st[N], idx; //领接表，用于存储图
int n, a, b;                       //获取输入
int ans = N;                       //最后的答案，因为往后要用min迭代，所以先尽可能的大，这里理解为无限大也行

void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
    return;
}

int dfs(int x)
{
    st[x] = true;
    int SIZE = 0, res = 0; //SIZE是以x为根节点的树的元素数，res是以x点为分割点分开以后最大的一个树的大小
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (st[j])
            continue;
        int s = dfs(j);    //s为以j结点为根结点的树的大小
        res = max(s, res); //和以前最大的子树比，谁大
        SIZE += s;         //这些子树都是这个大树的一部分，所以都要加上
    }
    SIZE++;                   //最后，以x为根的大树还要加上他自己
    res = max(res, n - SIZE); //比较除去这个子树以后的数的大小，同样取最大
    ans = min(res, ans);      //比较原来最小的最大子树和这次的，谁小迭代成谁
    return SIZE;              //返回此子树的大小
}

int main()
{
    cin >> n;
    memset(h, -1, sizeof h);
    for (int i = 1; i < n; ++i)
    {
        cin >> a >> b;
        add(a, b);
        add(b, a);
    }
    dfs(1);
    cout << ans;
    return 0;
}

//下面是面向对象的写法
/*
#include <iostream>
#include <cstring>
using namespace std;

const int N = 100010;
const int M = N * 2;
int n, a, b; //用来存储各个输入

class my_graph
{
private:
    int h[N];    //邻接表表头，每一个都表示一个链表表头，这个表是为了存储每个点可以一步到达的点
    int e[M];    //给邻接表预分配的空间，因为这个是用来存储树的，有n个点就有n-1条边，因为是双向边，点最多是N，所以边最多是2*(N-1)条
    int ne[M];   //记录每个点的下一个点，所以有多少边，就有多少ne
    int SIZE[N]; //树的每个结点的为根的子树的大小
    bool st[N];  //记录此点遍历过没
    int n;       //记录有多少个点
    int idx;     //记录邻接表的下一个可开拓的空间在哪
    int min_max; //最小的最大分块，树的重心对应的最大分块

public:
    my_graph(int x);        //初始化图的一些数据
    void add(int a, int b); //添加a->b的单向边
    void dfs(int u);        //深度有限遍历图
    int center();           //返回min_max
};

my_graph::my_graph(int x)
{
    n = x;                        //记录图中的节点数
    memset(h, -1, sizeof h);      //将每个结点都直接接空，既每个结点独立
    memset(st, false, sizeof st); //每个结点都没被遍历
    idx = 0;                      //因为邻接表里面一个没加，所以在0处插入第一个结点
    min_max = N;                  //先预设最大
}

void my_graph::add(int a, int b)
{
    e[idx] = b;     //首先吧b存储入新的结点中
    ne[idx] = h[a]; //然后这个结点记录未来插入的位置后部
    h[a] = idx++;   //将前部连接
    return;
}

void my_graph::dfs(int u)
{
    st[u] = true; //标记已经遍历
    int res = 0;  //去掉u后，最大的结点
    SIZE[u] = 0;  //先预设这个结点的子节点的大小
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];            //记录下一步结点
        if (st[j])               //如果遍历过
            continue;            //就直接跳过
        dfs(j);                  //不然就遍历他
        SIZE[u] += SIZE[j];      //而且将子树的大小添加到自己
        res = max(res, SIZE[j]); //找到最大的子树
    }
    SIZE[u]++;                   //加上自己
    res = max(res, n - SIZE[u]); //当然，也要对比去掉自己后的那个子树
    min_max = min(min_max, res); //这个的最大后，和以前的最小对比
    return;
}

int my_graph::center()
{
    return min_max;
}

int main()
{
    cin >> n;
    my_graph G(n);
    for (int i = 1; i < n; ++i)
    {
        cin >> a >> b;
        G.add(a, b);
        G.add(b, a); //因为树是无向表，所以要加上反向
    }
    G.dfs(a);           //从最初结点开始，其实从哪个开始无所谓，只是因为一定有1而已，a或者b应该也行
    cout << G.center(); //输出结果
    return 0;
}
*/